package com.ete.service.service.log

import android.Manifest
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.PermissionUtils
import com.blankj.utilcode.util.ThreadUtils
import com.ete.service.callback.log.IZipCallback
import com.ete.service.manager.ManagerConstant
import com.ete.service.manager.log.LogManager
import com.ete.service.service.R
import com.ete.service.util.SystemLogUtil
import com.ete.service.util.log.EteLog
import net.lingala.zip4j.exception.ZipException
import net.lingala.zip4j.model.ZipParameters
import net.lingala.zip4j.util.Zip4jConstants
import java.io.File

/**
 * Author:LiXian
 * <p>
 * Desc:压缩文件
 * Version:1.0
 * date 2024/1/8 13:42
 */
object ZipFileUtil {

    private var mTask: ThreadUtils.SimpleTask<String>? = null
    private var mZipProgress: ZipProgress? = null

    /**
     * (有密码)压缩文件夹或者文件
     * @param fromZipPathList 待压缩的文件夹或文件全路径
     * @param toZipPath 压缩到的文件路径...zip
     * @param zipPassword 压缩密码（若为null，则无密码）
     */
    @JvmStatic
    @JvmOverloads
    fun zipDirFile(
        fromZipPathList: MutableList<String>,
        toZipPath: String,
        callback: IZipCallback,
        zipPassword: String? = null
    ) {
        EteLog.d(LogManager.TAG, "Compress filePathList, $fromZipPathList")
        if (!PermissionUtils.isGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            EteLog.d(LogManager.TAG, "无读写权限")
            callback.onError(
                ManagerConstant.ERROR_ONT_PERMISSION,
                UploadLogUtil.getString(R.string.upload_not_permission)
            )
            return
        }

        val finalPathList = mutableListOf<String>()
        fromZipPathList.forEach {
            if (FileUtils.isFileExists(it)) {
                finalPathList.add(it)
            } else {
                EteLog.d(LogManager.TAG, "压缩文件/目录不存在, 目录:$it")
            }
        }


        // 全部目录都不存在, 才提示文件源不存在
        if (finalPathList.isEmpty()) {
            EteLog.d(LogManager.TAG, "所有压缩文件/目录源不存在, 无法压缩, 目录:$fromZipPathList")
            callback.onError(
                ManagerConstant.ERROR_ONT_SCR_FILE,
                UploadLogUtil.getString(R.string.upload_zip_file_not_exists)
            )
            return
        }

        if (FileUtils.isFileExists(toZipPath)) {
            EteLog.d(LogManager.TAG, "压缩文件已存在")
            callback.onSuccess(finalPathList, toZipPath)
            return
        }
        cancelTask()
        callback.onStart()
        mTask = object : ThreadUtils.SimpleTask<String>() {
            override fun doInBackground(): String {
                startZipFile(finalPathList, toZipPath, callback, zipPassword)
                return ""
            }

            override fun onSuccess(result: String?) {
                EteLog.d(LogManager.TAG, "解压任务成功")
                cancelTask()
            }

            override fun onFail(t: Throwable?) {
                super.onFail(t)
                EteLog.d(LogManager.TAG, "解压任务失败error:[${t?.message}]")
                cancelTask()
            }

            override fun onDone() {
                super.onDone()
                EteLog.d(LogManager.TAG, "解压任务完成")
                cancelTask()
            }
        }
        ThreadUtils.executeByIo(mTask)
    }

    @JvmStatic
    private fun startZipFile(
        fromZipPathList: MutableList<String>,
        toZipPath: String,
        callback: IZipCallback,
        zipPassword: String? = null
    ) {
        val result = SystemLogUtil.shell.run("su")
        EteLog.d(LogManager.TAG, "执行su命令isSuccess:[${result.isSuccess}]")
        fromZipPathList.forEach {
            val result2 = SystemLogUtil.shell.run("chmod -R 777 $it")
            EteLog.d(LogManager.TAG, "执行shell命令result:[$result2],path:[$it]")
        }
        val toFile = File(toZipPath)
        mZipProgress = ZipProgress(fromZipPathList, toZipPath, callback)
        try {
            val zipFile = ZipFile(toFile, mZipProgress)
            //设置编码格式（支持中文）
            zipFile.setFileNameCharset("GBK")
            val zipParameters = ZipParameters()
            zipParameters.compressionMethod = Zip4jConstants.COMP_DEFLATE
            zipParameters.compressionLevel = Zip4jConstants.DEFLATE_LEVEL_NORMAL
            //是否要加密(加密会影响压缩速度)
            if (!zipPassword.isNullOrEmpty()) {
                zipParameters.isEncryptFiles = true
                //加密方式
                zipParameters.encryptionMethod = Zip4jConstants.ENC_METHOD_STANDARD
                zipParameters.setPassword(zipPassword)
            }

            fromZipPathList.forEach {
                val fromFile = File(it)
                //压缩文件夹
                if (fromFile.isDirectory) {
                    zipFile.addFolder(fromFile, zipParameters)
                }
                //压缩文件
                else {
                    zipFile.addFile(fromFile, zipParameters)
                }
            }

        } catch (ex: Exception) {
            ex.printStackTrace()
            EteLog.d(LogManager.TAG, "压缩文件夹错误error:[${ex.message}]")
            FileUtils.delete(toZipPath)
        }
    }

    /**
     * (有密码)解缩文件夹或者文件
     * @param fromZipPath 压缩到的文件路径....zip
     * @param toZipPath 解压的文件夹路径
     * @param zipPassword 压缩密码（若为null，则无密码）
     */
    @JvmStatic
    @JvmOverloads
    fun unZipDirFile(
        fromZipPath: String,
        toZipPath: String,
        callback: IZipCallback,
        zipPassword: String? = null
    ) {
        val fromFile = File(fromZipPath)
        val toFile = File(toZipPath)
        try {
            mZipProgress = ZipProgress(mutableListOf(fromZipPath), toZipPath, callback)
            val zipFile = ZipFile(fromFile, mZipProgress)
            //设置编码格式（支持中文）
            zipFile.setFileNameCharset("GBK")
            //检查输入的zip文件是否是有效的zip文件
            if (!zipFile.isValidZipFile) {
                throw ZipException("压缩文件不合法,可能被损坏")
            }
            //创建解压至的文件夹
            if (toFile.isDirectory && !toFile.exists()) {
                toFile.mkdir()
            }
            //压缩包是否加密
            if (zipFile.isEncrypted) {
                if (zipPassword.isNullOrEmpty()) {
                    throw ZipException("压缩文件已加密，请输入密码")
                }
                zipFile.setPassword(zipPassword)
            }
            //解压至文件夹
            zipFile.extractAll(toZipPath);
        } catch (ex: ZipException) {
            EteLog.e(LogManager.TAG, "解压异常error:[${ex.message}]")
        }
    }

    @JvmStatic
    fun cancelTask() {
        EteLog.d(LogManager.TAG, "取消压缩日志任务")
        mZipProgress?.isPause = true
        mZipProgress?.cancelAllTasks()
        mZipProgress?.fullReset()
        mZipProgress = null
        mTask?.cancel()
        mTask = null
    }
}